var CryptoJS = require("./crypto/cryptojs-aes.min.js")
var utils = {};
var char="abcdefghijklmnopqrstuvwxyz1234567890";
var numeric_chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];

var hex_chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];

utils.normaliseHex = function (raw) {
  var value = raw.replace(/\s/g, '');
  value = value.toUpperCase();
  return value;
}

utils.byteArrayToWordArray = function (ba) {
  var wa = [],i;
  for (i = 0; i < ba.length; i++) {
    wa[(i / 4) | 0] |= ba[i] << (24 - 8 * i);
  }
  return CryptoJS.lib.WordArray.create(wa, ba.length);
}

utils.hexToBytes = function (str) {
  var result = [];
  while (str.length >= 2) {
    result.push(parseInt(str.substring(0, 2), 16));
    str = str.substring(2, str.length);
  }
  return result;
}

utils.bytesToHex = function (bytes) {
  for (var hex = [], i = 0; i < bytes.length; i++) {
    hex.push((bytes[i] >>> 4).toString(16));
    hex.push((bytes[i] & 0xF).toString(16));
  }
  return hex.join("");
}

utils.bigIntegerToHexString = function (x) {
  var hexString = x.toString(16);
  return hexString;
}

utils.toAsciiCodes = function (text) {
  var bytes = [];
  for (var i = 0; i < text.length; i++) {
    bytes.push(text.charCodeAt(i));
  }
  return bytes;
}

utils.toHex = function (number, octets) {
  var hex = ("0" + (Number(number).toString(16))).toUpperCase();
  if (hex.length % 2 == 1) {
    hex = "0" + hex;
  }
  var octet_count = hex.length / 2;
  if (octet_count < octets) {
    let added_zeroes = octets - octet_count;
    for (var i = 0; i < added_zeroes; i++) {
      hex = "00" + hex;
    }
  } else if (octet_count > octets) {
    hex = hex.substring((octet_count - octets) * 2, hex_chars.length);
  }
  return hex;
}

utils.hexToU8A = function (hex) {
  if (hex.length % 2 != 0) {
    console.log("ERROR: hex string must be even number in length and contain nothing but hex chars");
    return;
  }
  
  var bytes = [];
  for (var i = 0; i < hex.length; i = i + 2) {
    bytes.push(parseInt(hex.substring(i, i + 2), 16));
  }
  var result = new Uint8Array(bytes);
  return result;
}

utils.u8AToHexString = function (u8a) {
  var hex = '';
  for (var i = 0; i < u8a.length; i++) {
    let hex_pair = ('0' + u8a[i].toString(16));
    if (hex_pair.length == 3) {
      hex_pair = hex_pair.substring(1, 3);
    }
    hex = hex + hex_pair;
  }
  return hex;
}

// Convert an integer to a hex string, padded with a leading zero if required;
utils.intToHex = function (number) {
  var hex = "00" + number.toString(16);
  return hex.substring(hex.length - 2);
}

utils.xorU8Array = function (bytes1, bytes2) {
  // Uint8Arrays in and out
  if (bytes1.length != bytes2.length) {
    console.warn("ERROR in xorU8Array: operands must be the same length");
    return new Uint8Array([]);
  }
  var xor_bytes = [];
  for (var i = 0; i < bytes1.length; i++) {
    xor_bytes.push(bytes1[i] ^ bytes2[i]);
  }
  return new Uint8Array(xor_bytes);
}

utils.leastSignificantBit = function (hexString,length) {
  return parseInt(hexString, 16) & (Math.pow(2, length) - 1);
}
utils.arrayUnion = function (array1,array2) {
  return array1.filter(function(i){
    return array2.indexOf(i) == -1;
  })
}
utils.range = function (n) {
  var array=[];
  for(let i=0;i<n;i++){
    array.push(i);
  }
  return array;
}
utils.randomString=function(length){
  var str=""
  for(let i=0;i<length;i++){
    str += char[Math.floor(Math.random() * char.length)];
  }
  return str;
}
utils.randomNumber = function (length) {
  var str = ""
  for (let i = 0; i < length; i++) {
    str += numeric_chars[Math.floor(Math.random() * numeric_chars.length)];
  }
  return str;
}
utils.inherits=function(Parent,Child){
  var fn=function(){}
  fn.prototype=Parent.prototype;
  Child.prototype=new fn();
  Child.prototype.constructor = Child;
}
utils.randomHexString=function(){
  var rand=Math.floor(Math.random() * 256)
  return this.intToHex(rand);
}
utils.getLittleEndianString=function(str){
  if (str.length % 2 != 0) {
    console.log("ERROR: hex string must be even number in length and contain nothing but hex chars");
    return;
  }
  var littleEndianString="";
  for (let i = str.length - 2; i >= 0; i = i - 2) {
    littleEndianString += str.substr(i, 2);
  }
  return littleEndianString;
}
utils.getOpcodeAndParams=function(hex_access_payload) {
  var result = {
    opcode: "",
    params: "",
    company_code: "",
    status: -1,
    message: "Invalid parameter length"
  };

  if (hex_access_payload.length < 2) {
    return result;
  }

  var byte1 = parseInt(hex_access_payload.substring(0, 2), 16);

  if ((byte1 & 0x7F) == 0x7F) {
    result.message = "Opcode value is reserved for future use";
    return result;
  }

  result.status = 0;
  result.message = "OK";

  var opcode_len = 1;
  if ((byte1 & 0x80) == 0x80 && (byte1 & 0x40) != 0x40) {
    opcode_len = 2;
  } else if ((byte1 & 0x80) == 0x80 && (byte1 & 0x40) == 0x40) {
    opcode_len = 3;
  }

  var opcode_part = hex_access_payload.substring(0, (2 * opcode_len));
  var company_code = "";
  if (opcode_len == 3) {
    company_code = opcode_part.substring(2, 6);
    opcode_part = opcode_part.substring(0, 2);
    var opcode = parseInt(opcode_part, 16);
    result.company_code = company_code;
    result.opcode = this.toHex(opcode, 1);
  } else if (opcode_len == 2) {
    var opcode = parseInt(opcode_part, 16);
    result.opcode = this.toHex(opcode, 2);
  } else {
    var opcode = parseInt(opcode_part, 16);
    result.opcode = this.toHex(opcode, 1);
  }

  result.params = hex_access_payload.substring((2 * opcode_len), hex_access_payload.length);

  return result;
}

module.exports = utils;